package graphics;

import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.util.ArrayList;
import java.util.List;

import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCanvas;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.glu.GLU;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JRadioButtonMenuItem;

import music.Song;

import com.sun.opengl.util.Animator;
import com.sun.opengl.util.GLUT;

import core.Player;

public class Engine extends Thread implements ActionListener, GLEventListener,
		KeyListener, MouseMotionListener {
	float rotateT = 0.0f;
	float dir = (float) Math.PI;
	float lookDirZ = 0.0f;
	float lookDirY = 0.0f;
	float posX = 0.0f;
	float posY = -1.0f;
	float posZ = 4.0f;
	static GLU glu = new GLU();
	static GLCanvas canvas = new GLCanvas();
	static JFrame frame = new JFrame("Jogl 3D Shape/Rotation");
	static Animator animator = new Animator(canvas);
	int lastMousePosX = 320;
	private List<Player> players = new ArrayList<Player>();
	JMenuBar menuBar;
	JMenu menu, submenu;
	JMenuItem menuItem;
	JRadioButtonMenuItem rbMenuItem;
	JCheckBoxMenuItem cbMenuItem;
	Song song;
	GLUT glut = new GLUT();
	long lastMillis = 0;

	public void addPlayer(Player player) {
		players.add(player);
	}

	public void display(GLAutoDrawable gLDrawable) {
		final GL gl = gLDrawable.getGL();
		gl.glClear(GL.GL_COLOR_BUFFER_BIT);
		gl.glClear(GL.GL_DEPTH_BUFFER_BIT);
		gl.glLoadIdentity();
		gl.glRotatef((float) ((dir + lookDirY) * 180 / Math.PI), 0.0f, 1.0f,
				0.0f);
		gl.glTranslatef(posX, posY, posZ);

		gl.glClear(GL.GL_COLOR_BUFFER_BIT);
		for (Player player : players) {
			player.display(gl);
			player.update();
		}
		gl.glRasterPos3f(-1.0f, -0.3f, 0.0f);
		long thisMillis = System.nanoTime();
		float fps = 1000000000.0f/(float) (thisMillis - lastMillis);
		glut.glutBitmapString(GLUT.BITMAP_TIMES_ROMAN_10, "FPS:" + fps);
		lastMillis = thisMillis;
	}

	public void displayChanged(GLAutoDrawable gLDrawable, boolean modeChanged,
			boolean deviceChanged) {
	}

	public void init(GLAutoDrawable gLDrawable) {
		GL gl = gLDrawable.getGL();
		gl.glEnable(GL.GL_LINE_SMOOTH);
		gl.glEnable(GL.GL_BLEND);
		gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);
		gl.glHint(GL.GL_LINE_SMOOTH_HINT, GL.GL_DONT_CARE);
		gl.glLineWidth(1.5f);
		gl.glShadeModel(GL.GL_SMOOTH);
		gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
		gl.glClearDepth(1.0f);
		gl.glEnable(GL.GL_DEPTH_TEST);
		gl.glDepthFunc(GL.GL_LEQUAL);
		gl.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST);
		gLDrawable.addKeyListener(this);
		gLDrawable.addMouseMotionListener(this);

	}

	public void reshape(GLAutoDrawable gLDrawable, int x, int y, int width,
			int height) {
		GL gl = gLDrawable.getGL();
		if (height <= 0) {
			height = 1;
		}
		float h = (float) width / (float) height;
		gl.glMatrixMode(GL.GL_PROJECTION);
		gl.glLoadIdentity();
		glu.gluPerspective(50.0f, h, 1.0, 1000.0);
		gl.glMatrixMode(GL.GL_MODELVIEW);
		gl.glLoadIdentity();
	}

	public void keyPressed(KeyEvent e) {
		switch (e.getKeyCode()) {
		case KeyEvent.VK_ESCAPE:
			exit();
			break;
		case KeyEvent.VK_D:
			stepFwd(0.2f);
			dir += lookDirY / 10;
			break;
		case KeyEvent.VK_X:
			stepBack(0.2f);
			dir -= lookDirY / 10;
			break;
		case KeyEvent.VK_S:
			stepLeft(0.2f);
			break;
		case KeyEvent.VK_C:
			stepRight(0.2f);
			break;

//		case KeyEvent.VK_E:
//			dir += 0.1f;
//			break;
//		case KeyEvent.VK_Q:
//			dir -= 0.1f;
//			break;
		case KeyEvent.VK_O:
			movePlayer(0, -0.5f);
			break;
		case KeyEvent.VK_P:
			movePlayer(0, 0.5f);
			break;
		case KeyEvent.VK_K:
			rotatePlayer(0, -0.5f);
			break;
		case KeyEvent.VK_L:
			rotatePlayer(0, 0.5f);
			break;
		case KeyEvent.VK_SPACE:
			song.start();
			break;
		default:
			break;
		}
		for (Player player : players) {
			for (int i = 0; i < 5; i++)
				if (player.getGuitarKeys().getKeyCode(i) == e.getKeyCode())
					player.getGuitarKeys().setKey(i);
			if (player.getGuitarKeys().getHitKeyCode() == e.getKeyCode())
				player.hit();
		}
	}

	private void movePlayer(int i, float x) {
		players.get(i).setOffsetX(players.get(i).getOffsetX() + x);
	}

	private void rotatePlayer(int i, float x) {
		players.get(i).setRotationY(players.get(i).getRotationY() + x);
	}

	private void stepFwd(float f) {
		// TODO Auto-generated method stub
		posZ += f * Math.cos(-dir);
		posX += f * Math.sin(-dir);
	}

	private void stepBack(float f) {
		// TODO Auto-generated method stub
		posZ += f * -Math.cos(-dir);
		posX += f * -Math.sin(-dir);
	}

	private void stepLeft(float f) {
		// TODO Auto-generated method stub
		posZ += f * -Math.cos(-dir - Math.PI / 2);
		posX += f * -Math.sin(-dir - Math.PI / 2);
	}

	private void stepRight(float f) {
		// TODO Auto-generated method stub
		posZ += f * -Math.cos(-dir + Math.PI / 2);
		posX += f * -Math.sin(-dir + Math.PI / 2);
	}

	public void keyReleased(KeyEvent e) {
		for (Player player : players) {
			for (int i = 0; i < 5; i++)
				if (player.getGuitarKeys().getKeyCode(i) == e.getKeyCode())
					player.getGuitarKeys().unSetKey(i);
		}
	}

	public void keyTyped(KeyEvent e) {
	}

	public static void exit() {
		animator.stop();
		frame.dispose();
		System.exit(0);
	}

	public void run() {
		canvas.addGLEventListener(this);
		//addMenu(this);

		frame.add(canvas);
		frame.setSize(640, 480);
		frame.setUndecorated(false);
		frame.setExtendedState(Frame.NORMAL);
		frame.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				exit();
			}
		});
		frame.setVisible(true);
		animator.start();
		canvas.requestFocus();
	}

	private void addMenu(ActionListener actionListener) {
		// Create the menu bar.
		menuBar = new JMenuBar();

		// Build the first menu.
		menu = new JMenu("Songs");
		menuBar.add(menu);

		// a submenu
		menu.addSeparator();
		submenu = new JMenu("Guitar Hero");
		menu.add(submenu);
		
		frame.setJMenuBar(menuBar);
	}

	@Override
	public void mouseDragged(MouseEvent e) {
		// TODO Auto-generated method stub

	}

	@Override
	public void mouseMoved(MouseEvent e) {
		// TODO Auto-generated method stub
		// lookDirY = (float) (e.getX() - 320) / 640;
		// lookDirZ = (float) (e.getY() - 240) / 480;
		// lastMousePosX = e.getX();
	}

	public void setSong(String songDir) {
		song = new Song(songDir);
		for (Player player : players) {
			player.setSong(song);
		}
	}

	@Override
	public void actionPerformed(ActionEvent arg0) {
		// TODO Auto-generated method stub
		String actionCommand = arg0.getActionCommand();
		System.out.println(arg0.getActionCommand());
		setSong(actionCommand);
	}

	public void addSong(File songDir) {
		// TODO Auto-generated method stub
		if(menuBar == null)
			addMenu(this);
		menuItem = new JMenuItem(songDir.getName());
		menuItem.addActionListener(this);
		menuItem.setActionCommand(songDir.getAbsolutePath());
		submenu.add(menuItem);
	}
}
